bitkeeper revision 1.670 (3ffaf723Sn5FVTMBSOvb9binR3cthQ)
authorkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Tue, 6 Jan 2004 17:57:55 +0000 (17:57 +0000)
committerkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Tue, 6 Jan 2004 17:57:55 +0000 (17:57 +0000)
network.c, dev.c, pgalloc.h, flushtlb.h, domain.c, smp.c:
  Fixed heinous TLB-flush and network bugs.

xen/arch/i386/smp.c
xen/common/domain.c
xen/include/asm-i386/flushtlb.h
xen/include/asm-i386/pgalloc.h
xen/net/dev.c
xenolinux-2.4.23-sparse/arch/xeno/drivers/network/network.c

index 4ec5176194a6dd616104e833554b599233d84645..f60a42dd0cb64b1f9a718408c0a9843e1dcbd962 100644 (file)
@@ -269,8 +269,34 @@ asmlinkage void smp_invalidate_interrupt(void)
     local_flush_tlb();
 }
 
+int try_flush_tlb_mask(unsigned long mask)
+{
+    if ( mask & (1 << smp_processor_id()) )
+    {
+        local_flush_tlb();
+        mask &= ~(1 << smp_processor_id());
+    }
+
+    if ( mask != 0 )
+    {
+        if ( unlikely(!spin_trylock(&tlbstate_lock)) )
+            return 0;
+        flush_cpumask = mask;
+        send_IPI_mask(mask, INVALIDATE_TLB_VECTOR);
+        while ( flush_cpumask != 0 )
+        {
+            rep_nop();
+            barrier();
+        }
+        spin_unlock(&tlbstate_lock);
+    }
+
+    return 1;
+}
+
 void flush_tlb_mask(unsigned long mask)
 {
+    /* WARNING: Only try_flush_tlb_mask() is safe in IRQ context. */
     if ( unlikely(in_irq()) )
         BUG();
     
index 9cb4437d701d9e12d932693d1207f0842a501f06..147d9c0f97120a433ef2d70b3fb1ec3315c8790b 100644 (file)
@@ -17,7 +17,6 @@
 #include <xeno/blkdev.h>
 #include <xeno/console.h>
 #include <xeno/vbd.h>
-
 #include <asm/i387.h>
 
 /*
@@ -237,12 +236,12 @@ struct pfn_info *alloc_domain_page(struct task_struct *p)
     if ( unlikely(page == NULL) )
         return NULL;
 
-    if ( unlikely((mask = page->u.cpu_mask) != 0) )
+    if ( (mask = page->u.cpu_mask) != 0 )
     {
         pfn_stamp = page->tlbflush_timestamp;
         for ( i = 0; (mask != 0) && (i < NR_CPUS); i++ )
         {
-            if ( unlikely(mask & (1<<i)) )
+            if ( mask & (1<<i) )
             {
                 cpu_stamp = tlbflush_time[i];
                 if ( !NEED_FLUSH(cpu_stamp, pfn_stamp) )
@@ -252,13 +251,12 @@ struct pfn_info *alloc_domain_page(struct task_struct *p)
 
         if ( unlikely(mask != 0) )
         {
-            if ( unlikely(in_irq()) )
-            {
-                DPRINTK("Returning NULL from alloc_domain_page: in_irq\n");
+            /* In IRQ ctxt, flushing is best-effort only, to avoid deadlock. */
+            if ( likely(!in_irq()) )
+                flush_tlb_mask(mask);
+            else if ( unlikely(!try_flush_tlb_mask(mask)) )
                 goto free_and_exit;
-            }
             perfc_incrc(need_flush_tlb_flush);
-            flush_tlb_mask(mask);
         }
     }
 
index e6f61cb521e5314bf4e79d36eba9f0f812a3af45..49760ef70ce80b6954b6b72840fad2e6f850a1f5 100644 (file)
@@ -24,8 +24,8 @@
  * used for a purpose that may have caused the CPU's TLB to become tainted.
  */
 #define NEED_FLUSH(_cpu_stamp, _lastuse_stamp) \
- (((_cpu_stamp) > (_lastuse_stamp)) ||         \
-  (((_lastuse_stamp) - (_cpu_stamp)) > (2*GLOBAL_FLUSH_PERIOD)))
+ (((_cpu_stamp) <= (_lastuse_stamp)) &&        \
+  (((_lastuse_stamp) - (_cpu_stamp)) <= (2*GLOBAL_FLUSH_PERIOD)))
 
 extern unsigned long tlbflush_mask;
 extern unsigned long tlbflush_clock;
index 88e906464119617448db34f527a3b95f1cdb65fe..6f01b44441c4064d467e096fddfb37bd7440b94e 100644 (file)
 
 #ifndef CONFIG_SMP
 
-#define flush_tlb()           __flush_tlb()
-#define flush_tlb_all()       __flush_tlb()
-#define flush_tlb_all_pge()   __flush_tlb_pge()
-#define local_flush_tlb()     __flush_tlb()
-#define flush_tlb_cpu(_cpu)   __flush_tlb()
-#define flush_tlb_mask(_mask) __flush_tlb()
+#define flush_tlb()               __flush_tlb()
+#define flush_tlb_all()           __flush_tlb()
+#define flush_tlb_all_pge()       __flush_tlb_pge()
+#define local_flush_tlb()         __flush_tlb()
+#define flush_tlb_cpu(_cpu)       __flush_tlb()
+#define flush_tlb_mask(_mask)     __flush_tlb()
+#define try_flush_tlb_mask(_mask) __flush_tlb()
 
 #else
 
 #include <xeno/smp.h>
 
+extern int try_flush_tlb_mask(unsigned long mask);
 extern void flush_tlb_mask(unsigned long mask);
 extern void flush_tlb_all_pge(void);
 
index a20a0ee6cd8f24cd392145657143da0f095e4749..936d40f04c555f45a3ec9f9c047ffce3d39e47ef 100644 (file)
@@ -535,6 +535,7 @@ void deliver_packet(struct sk_buff *skb, net_vif_t *vif)
                           (pte & ~PAGE_MASK) | _PAGE_RW | _PAGE_PRESENT |
                           ((new_page - frame_table) << PAGE_SHIFT))) != pte )
     {
+        DPRINTK("PTE was modified or reused! %08lx %08lx\n", pte, *ptep);
         unmap_domain_mem(ptep);
         /* At some point maybe should have 'new_page' in error response. */
         put_page_and_type(new_page);
@@ -2112,6 +2113,9 @@ static void get_rx_bufs(net_vif_t *vif)
             goto rx_unmap_and_continue;
         }
             
+        buf_page->tlbflush_timestamp = tlbflush_clock;
+        buf_page->u.cpu_mask = 1 << p->processor;
+
         /* Remove from the domain's allocation list. */
         spin_lock(&p->page_list_lock);
         list_del(&buf_page->list);
@@ -2167,7 +2171,7 @@ long flush_bufs_for_vif(net_vif_t *vif)
     for ( i = vif->rx_req_cons; 
           (i != shared_idxs->rx_req_prod) &&
               ((i-vif->rx_resp_prod) != RX_RING_SIZE);
-          i++ );
+          i++ )
     {
         make_rx_response(vif, shared_rings->rx_ring[MASK_NET_RX_IDX(i)].req.id,
                          0, RING_STATUS_DROPPED, 0);
@@ -2179,6 +2183,7 @@ long flush_bufs_for_vif(net_vif_t *vif)
 
         /* Give the buffer page back to the domain. */
         page = &frame_table[rx->buf_pfn];
+        page->u.domain = p;
         spin_lock(&p->page_list_lock);
         list_add(&page->list, &p->page_list);
         page->count_and_flags = PGC_allocated | 2;
@@ -2194,7 +2199,10 @@ long flush_bufs_for_vif(net_vif_t *vif)
              unlikely(cmpxchg(ptep, pte, (rx->buf_pfn<<PAGE_SHIFT) | 
                               (pte & ~PAGE_MASK) | _PAGE_RW | _PAGE_PRESENT)
                       != pte) )
+        {
+            DPRINTK("PTE was modified or reused! %08lx %08lx\n", pte, *ptep);
             put_page_and_type(page);
+        }
         unmap_domain_mem(ptep);
 
         put_page_and_type(&frame_table[rx->pte_ptr >> PAGE_SHIFT]);
index 492a2cc881d542a1166daaa2789d0a66c83dde67..ac557a3c11f12ce16315b38da2672879000759ab 100644 (file)
@@ -60,8 +60,8 @@ struct net_private
      * {tx,rx}_skbs store outstanding skbuffs. The first entry in each
      * array is an index into a chain of free entries.
      */
-    struct sk_buff *tx_skbs[TX_RING_SIZE];
-    struct sk_buff *rx_skbs[RX_RING_SIZE];
+    struct sk_buff *tx_skbs[TX_RING_SIZE+1];
+    struct sk_buff *rx_skbs[RX_RING_SIZE+1];
 };
 
 /* Access macros for acquiring freeing slots in {tx,rx}_skbs[]. */
@@ -145,9 +145,9 @@ static int network_open(struct net_device *dev)
     memset(np->net_idx, 0, sizeof(*np->net_idx));
 
     /* Initialise {tx,rx}_skbs to be a free chain containing every entry. */
-    for ( i = 0; i < TX_RING_SIZE; i++ )
+    for ( i = 0; i <= TX_RING_SIZE; i++ )
         np->tx_skbs[i] = (void *)(i+1);
-    for ( i = 0; i < RX_RING_SIZE; i++ )
+    for ( i = 0; i <= RX_RING_SIZE; i++ )
         np->rx_skbs[i] = (void *)(i+1);
 
     wmb();